package edu.gatech.bsbmule.view;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.BevelBorder;

import edu.gatech.bsbmule.model.CustomizedTimer;
import edu.gatech.bsbmule.model.Game;
import edu.gatech.bsbmule.model.Player;
import edu.gatech.bsbmule.model.Tile;

/**
 * The GUI component which displays tiles, player information and remaining time
 * 
 * @author BSB
 * @version 1.0 10/26/2013
 */
public class MapScreen extends JPanel implements IMapScreen {
    
	private Image riverImg;
	private Image townImg;
	private Image m1Img;
	private Image m2Img;
	private Image m3Img;
	private Image plainImg;
	private JLabel[][] labels;
	
	//Containers
	private JPanel gridPanel;
	private JPanel playerInfoPanel;
	
	//Log window
	private JTextArea logWindow;
	
	//Player info labels
	private JLabel nameLabel;
	private JLabel moneyLabel;
	private JLabel foodLabel;
	private JLabel energyLabel;
	private JLabel muleLabel;
	private JLabel timerLabel;
	
	//Status bar labels
	private JLabel turnLabel;
	private JLabel tradingStatusLabel;
	private JLabel freePropertyLabel;
	
	//Timer for one second to print time
	private Timer timer;
	
	//This boolean represents whether the tiles are in trading status (aka land office)
	private boolean inTrade;
	private boolean withMule;
	
	public static MapScreen instance = null;
	private JLabel lblNewLabel;
	
	public static MapScreen getInstance() throws IOException {
		if (instance == null) {
			instance = new MapScreen();
		}
		return instance;
	}
	
	/**
	 * Create the panel and load tile images
	 * 
	 * @throws IOException
	 */
	private MapScreen() throws IOException {
		
		setLayout(new BorderLayout());
		
		//Create containers for tile map and player info
		JSplitPane grandPane = new JSplitPane();
		grandPane.setEnabled(false);
		add(grandPane, BorderLayout.NORTH);

		gridPanel = new JPanel(new GridLayout(5, 9, 0, 0));
		grandPane.setLeftComponent(gridPanel);
		
		playerInfoPanel = new JPanel(new GridLayout(6, 2, 5, 0));
		grandPane.setRightComponent(playerInfoPanel);
		
		JLabel label = new JLabel("Name");
		label.setFont(new Font("Tahoma", Font.PLAIN, 16));
		playerInfoPanel.add(label);
		nameLabel = new JLabel("wait for init");
		nameLabel.setFont(new Font("Tahoma", Font.PLAIN, 16));
		label.setLabelFor(nameLabel);
		playerInfoPanel.add(nameLabel);
		
		JLabel label_1 = new JLabel("Money");
		label_1.setFont(new Font("Tahoma", Font.PLAIN, 16));
		playerInfoPanel.add(label_1);
		moneyLabel = new JLabel("wait for init");
		moneyLabel.setFont(new Font("Tahoma", Font.PLAIN, 16));
		label_1.setLabelFor(moneyLabel);
		playerInfoPanel.add(moneyLabel);
		
		JLabel label_2 = new JLabel("Food");
		label_2.setFont(new Font("Tahoma", Font.PLAIN, 16));
		playerInfoPanel.add(label_2);
		foodLabel= new JLabel("wait for init");
		foodLabel.setFont(new Font("Tahoma", Font.PLAIN, 16));
		label_2.setLabelFor(foodLabel);
		playerInfoPanel.add(foodLabel);
		
		JLabel label_3 = new JLabel("Energy");
		label_3.setFont(new Font("Tahoma", Font.PLAIN, 16));
		playerInfoPanel.add(label_3);
		energyLabel = new JLabel("wait for init");
		energyLabel.setFont(new Font("Tahoma", Font.PLAIN, 16));
		label_3.setLabelFor(energyLabel);
		playerInfoPanel.add(energyLabel);
		
		JLabel label_4 = new JLabel("Has M.U.L.E.");
		JLabel label_5 = new JLabel("Has M.U.L.E.");
		label_5.setFont(new Font("Tahoma", Font.PLAIN, 16));
		playerInfoPanel.add(label_5);
		muleLabel = new JLabel("wait for init");
		muleLabel.setFont(new Font("Tahoma", Font.PLAIN, 16));
		label_4.setLabelFor(muleLabel);
		playerInfoPanel.add(muleLabel);
		
		lblNewLabel = new JLabel("Time left");
		lblNewLabel.setFont(new Font("Tahoma", Font.PLAIN, 16));
		playerInfoPanel.add(lblNewLabel);
		
		timerLabel = new JLabel("wait for init");
		timerLabel.setForeground(Color.RED);
		timerLabel.setFont(new Font("Tahoma", Font.PLAIN, 32));
		playerInfoPanel.add(timerLabel);
		
		//Create status bar
		JPanel statusPane = new JPanel();
		statusPane.setBorder(new BevelBorder(BevelBorder.LOWERED));
		statusPane.setLayout(new BoxLayout(statusPane, BoxLayout.X_AXIS));
		JLabel label_6 = new JLabel("Turn: ");
		label_6.setFont(new Font("Tahoma", Font.PLAIN, 16));
		statusPane.add(label_6);
		turnLabel = new JLabel("1");
		turnLabel.setFont(new Font("Tahoma", Font.PLAIN, 16));
		statusPane.add(turnLabel);
		JLabel label_7 = new JLabel(" | Land Office: ");
		label_7.setFont(new Font("Tahoma", Font.PLAIN, 16));
		statusPane.add(label_7);
		tradingStatusLabel = new JLabel("NO");
		tradingStatusLabel.setFont(new Font("Tahoma", Font.PLAIN, 16));
		statusPane.add(tradingStatusLabel);
		JLabel label_8 = new JLabel(" | Free Property: ");
		label_8.setFont(new Font("Tahoma", Font.PLAIN, 16));
		statusPane.add(label_8);
		freePropertyLabel = new JLabel("YES");
		freePropertyLabel.setFont(new Font("Tahoma", Font.PLAIN, 16));
		statusPane.add(freePropertyLabel);
		add(statusPane, BorderLayout.SOUTH);
		
		//Pass button
		JButton btnPass = new JButton("PASS");
		btnPass.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				CustomizedTimer.getInstance().byPass();
			}
		});
		btnPass.setFont(new Font("Tahoma", Font.PLAIN, 24));
		
		//Create container for pass button and log window
		
		logWindow = new JTextArea("Welcome to M.U.L.E. by Backstreet Bytes\n");
		logWindow.setFont(new Font("Tahoma", Font.PLAIN, 12));
		logWindow.setEditable(false);
		logWindow.setPreferredSize(new Dimension(600, 100));
		JScrollPane scrollableWindow = new JScrollPane(logWindow, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
		
		JSplitPane midPane = new JSplitPane();
		midPane.setEnabled(false);
		midPane.setLeftComponent(scrollableWindow);
		midPane.setRightComponent(btnPass);
		add(midPane, BorderLayout.CENTER);		
		
		//Get file separator according to system specification (Windows or UNIX/Linux)
		String fs = File.separator;
		String rsc = "resources" + fs;
		File sourceimage1, sourceimage2, sourceimage3, sourceimage4, sourceimage5, sourceimage6;
		
		sourceimage1 = new File(rsc + "Plain.jpg");
		sourceimage2 = new File(rsc + "River.jpg");
		sourceimage3 = new File(rsc + "Town.jpg");
		sourceimage4 = new File(rsc + "Mountain1.jpg");
		sourceimage5 = new File(rsc + "Mountain2.jpg");
		sourceimage6 = new File(rsc + "Mountain3.jpg");
		
		plainImg = ImageIO.read(sourceimage1);
		riverImg = ImageIO.read(sourceimage2);
		townImg = ImageIO.read(sourceimage3);
		m1Img = ImageIO.read(sourceimage4);
		m2Img = ImageIO.read(sourceimage5);
		m3Img = ImageIO.read(sourceimage6);

		labels = new JLabel[5][9];
		
		inTrade = false;
	}
	
	/**
	 * @see edu.gatech.bsbmule.view.IMapScreen
	 */
	@Override
	public void displayTiles(Tile[][] tiles) {
		for (int i = 0; i < tiles.length; i++) {
			for (int j = 0; j < tiles[0].length; j++) {
				int terrain = tiles[i][j].getTerrain();
				ImageIcon targetIcon = null;
				if (terrain == 1) {
					targetIcon = new ImageIcon(townImg);
				} else if (terrain == 2) {
					targetIcon = new ImageIcon(plainImg);
				} else if (terrain == 3) {
					targetIcon = new ImageIcon(riverImg);
				} else if (terrain == 4) {
					targetIcon = new ImageIcon(m1Img);
				} else if (terrain == 5) {
					targetIcon = new ImageIcon(m2Img);
				} else {
					targetIcon = new ImageIcon(m3Img);
				}
				//Avoids town terrain
				JLabel targetLabel = new JLabel(targetIcon);
				targetLabel.setBorder(BorderFactory.createLineBorder(null, 5));
				labels[i][j] = targetLabel;
				gridPanel.add(targetLabel);
			}
		}
		setTownButtonListender(labels[2][4]);
	}
	
	/**
	 * Set a given JLabel to activate town window when clicked
	 * 
	 * @param town JLabel of town
	 */
	private void setTownButtonListender(JLabel town) {
		town.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				TownWindow townWindow = TownWindow.getInstance();
				townWindow.setVisible(true);
			}
		});
	}
	
	/**
	 * @see edu.gatech.bsbmule.view.IMapScreen
	 */
	@Override
	public void setTileListener(MouseAdapter e) {
		for (int i = 0; i < labels.length; i++) {
			for (int j = 0; j < labels[0].length; j++) {
				labels[i][j].addMouseListener(e);
			}
		}
	}
	
	/**
	 * @see edu.gatech.bsbmule.view.IMapScreen
	 */
	@Override
	public Point queryLocationByJLabel(JLabel label) {
		Point locationFound = null;
		for (int i = 0; i < labels.length; i++) {
			for (int j = 0; j < labels[0].length; j++) {
				//Check if the label is the EXACT SAME JLabel
				if (labels[i][j] == label) {
					locationFound = new Point(i,j);
				}
			}
		}
		return locationFound;
	}
	
	/**
	 * @see edu.gatech.bsb.view.IMapScreen
	 */
	@Override
	public void updateJLabelColor(Point point, Color color) {
		JLabel markedJLabel
			= labels[(int)point.getX()][(int)point.getY()];
		markedJLabel.setBorder(BorderFactory.createLineBorder(color, 5));
	}
	
	/**
	 * @see edu.gatech.bsb.view.IMapScreen
	 */
	@Override
	public void updatePlayerInfo(Player player) {
		nameLabel.setText(player.getName());
		moneyLabel.setText(Integer.toString(player.getMoney()));
		foodLabel.setText(Integer.toString(player.getFood()));
		energyLabel.setText(Integer.toString(player.getEnergy()));
		if (player.getMule() != null)
		{
			muleLabel.setText("YES");
		}
		else
		{
			muleLabel.setText("NO");
		}
		nameLabel.paintImmediately(nameLabel.getVisibleRect());
		moneyLabel.paintImmediately(moneyLabel.getVisibleRect());
		foodLabel.paintImmediately(foodLabel.getVisibleRect());
		energyLabel.paintImmediately(energyLabel.getVisibleRect());
		muleLabel.paintImmediately(muleLabel.getVisibleRect());
	}
	
	/**
	 * @see edu.gatech.bsb.view.IMapScreen
	 */
	@Override
	public boolean getIntrade() {
		return inTrade;
	}
	
	/**
	 * @see edu.gatech.bsb.view.IMapScreen
	 */
	@Override
	public void setIntrade(boolean inTrade) {
		this.inTrade = inTrade;
	}
	
	/**
	 * @greg javadoc this
	 */
	public boolean isWithMule() {
		return withMule;
	}
	
	/**
	 * @greg javadoc this
	 */
	public boolean hasMule(Player p){
		return p.getMule()!= null;
	}
	
	/**
	 * @greg javadoc this
	 */
	public void setWithMule(boolean withMule) {
		this.withMule = withMule;
	}
	
	/**
	 * @see edu.gatech.bsb.view.IMapScreen
	 */
	@Override
	public void startOneSecTimer() {
		timerLabel.setText(Integer.toString((int)(CustomizedTimer.getInstance().getRemainingTime() / 1000)) + "s");
		timerLabel.paintImmediately(timerLabel.getVisibleRect());
		timer = new Timer();
		timer.scheduleAtFixedRate(new TimerTask() {
			public void run() {
				if (!Game.getInstance().isEndOfTheGame())
				{
					timerLabel.setText(Integer.toString((int)(CustomizedTimer.getInstance().getRemainingTime() / 1000)) + "s");
					timerLabel.paintImmediately(timerLabel.getVisibleRect());
				}
			}
		}, 0, 50);
	}
	
	/**
	 * @see edu.gatech.bsb.view.IMapScreen
	 */
	@Override
	public void stopOneSecTimer() {
		timer.cancel();
	}
	
	/**
	 * @see edu.gatech.bsb.view.IMapScreen
	 */
	@Override
	public void setTurnStatus(String turn) {
		turnLabel.setText(turn);
		turnLabel.paintImmediately(turnLabel.getVisibleRect());
	}
	
	/**
	 * @see edu.gatech.bsb.view.IMapScreen
	 */
	@Override
	public void setTradingStatus(String trading) {
		tradingStatusLabel.setText(trading);
	}
	
	/**
	 * @see edu.gatech.bsb.view.IMapScreen
	 */
	@Override
	public void setFreePropertyStatus(String free) {
		freePropertyLabel.setText(free);
	}
	
	/**
	 * @see edu.gatech.bsb.view.IMapScreen
	 */
	@Override
	public void appendLog(String s) {
		logWindow.append(s);
	}
}
